home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Snippets
/
Stuart's Tech Notes
/
VirtualTemporaryMemory
< prev
Wrap
Text File
|
1996-06-01
|
5KB
|
116 lines
/*
VirtualTemporaryMemory
©1996 Stuart Cheshire <cheshire@CS.Stanford.EDU>
Sometimes a program can run in a small amount of memory, but can run a lot
faster if it has more memory available. Recently I wrote a program like this
called StUU (ftp://bolo.stanford.edu/Public/Stuart%27s%20tech%20notes/StUU/).
StUU is a super-fast UUdecoder. If there is only 1K of free memory, then StUU
can still decode the file correctly by reading 1K at a time from the disk,
but if there is 1MB or 10MB available, or more, then it can decode much
faster by reading larger blocks from the disk.
In StUU 1.0 I decided how much memory to use in the obvious way, by calling
TempMaxMem to see how much free temporary memory was available. This worked
fine on my Mac, but on Macs with RAM Doubler or Virtual Memory turned on it
locks up the Mac. The Mac is not crashed -- it is just thrashing the virtual
memory system so badly that it will take hours to finish decoding. One of
those cases where more is less.
So, how does a well written program decide how much memory to use?
After pondering this problem for a while, here is the solution I have come
up with:
If VM (and RAM Doubler) is off, then just use the normal TempMaxMem call,
else:
1. See how much "holdable" RAM is available. Holdable RAM is the subset of
Physical RAM that is available for applications to use.
2. Tentatively decide to use the amount of holdable RAM that is free (not
currently in use by any other program), or if the amount of free holdable
RAM is less than 1/16 of the total holdable RAM, tentatively decide to use
1/16 of the total holdable RAM (it's okay to steal a little back from other
applications).
3. If the amount that TempMaxMem told us to use is more than the amount
we have decided is safe (which is usually the case), we stick to our own
estimate and ignore TempMaxMem. If TempMaxMem tells us less is available
(which could happen if the Mac was *really* loaded and there really just
isn't any memory left) then we use the amount it says.
To summarise, the formula for the amount of memory to use is:
my_estimate = max(free holdable RAM, total holdable RAM / 16)
amount_to_use = min(TempMaxMem, my_estimate)
If you have an existing program that currently calls "TempMaxMem", just
paste these routines into it and call "sensibleTempMaxMem" instead.
NOTE: If your program decides to use all available RAM in this way, it MUST
do it only for a few seconds at most. If you hold the memory for a long time,
the user is going to be VERY annoyed when they find that their 64MB Mac
doesn't have enough free memory left even to launch TeachText. StUU, for
example, typically launches, finishes decoding, and quits in under ten seconds.
This, I think, is acceptable.
*/
#ifdef __MC68K__
// The definition of GetHoldableBytes for 68K code
#if !GENERATINGCFM
#pragma parameter __D0 GetHoldableBytes()
#endif
extern pascal Size GetHoldableBytes(void) TWOWORDINLINE(0x70FD, 0xA05C);
#else
// The definition of GetHoldableBytes for PPC code
static pascal Size GetHoldableBytes(void)
{
static short GetHoldableBytes68K[] =
{
0x70FD, // moveq #-3,d0
0xA05C, // MemoryDispatch
0x4E75, // rts
};
enum
{
uppGetHoldableBytesProcInfo = kRegisterBased
| RESULT_SIZE(kFourByteCode) | REGISTER_RESULT_LOCATION(kRegisterD0)
};
return(CallUniversalProc((UniversalProcPtr)GetHoldableBytes68K, uppGetHoldableBytesProcInfo));
}
#endif
static Size sensibleTempMaxMem(Size *grow)
{
Size freemem = TempMaxMem(grow);
long VMAttr, PhysicalRAM, LogicalRAM;
// if VM on, see if we can revise our estimate of free memory to a more sensible value
if (TrapAvailable(_Gestalt) &&
Gestalt(gestaltVMAttr, &VMAttr) == noErr && (VMAttr & (1 << gestaltVMPresent)) &&
Gestalt(gestaltPhysicalRAMSize, &PhysicalRAM) == noErr &&
Gestalt(gestaltLogicalRAMSize, &LogicalRAM) == noErr)
{
// See how much physical RAM is available
// If MemoryDispatch is available, use it, else just use
// a simplistic estimate that half of the physical RAM is holdable
Size holdable = TrapAvailable(_MemoryDispatch) ? GetHoldableBytes() : PhysicalRAM / 2;
// See how much memory is in use
Size usedmem = LogicalRAM - TempFreeMem();
// See how much physical RAM is free
Size useable = 0;
if (holdable > usedmem) useable = holdable - usedmem;
// If there is very little (or no) physical RAM left, then we'll
// steal 1/16 of the holdable pages (e.g. 1M on a 16M machine)
if (useable < holdable/16) useable = holdable/16;
// If our initial freemem value is more than this amount
// that we deem sensible to allocate, reduce it
if (freemem > useable) freemem = useable;
}
return(freemem);
}